# -*- coding: utf-8 -*-
import os
import re
import sys
import logging
import numpy as np


TIME_START_KEY = 'Time from start of output'

class LocalException(Exception):
    def __init__(self, msg=None, reason=None, rc=-1):
        Exception.__init__(self)
        self.msg = msg
        self.reason = reason
        self.rc = rc

    def set_reason(self, value):
        self.reason = value


SUCCESS = LocalException(rc=0)
PARAMETER_EX = LocalException(msg='need task path or task path is not exist',
                              rc=1)
KMXURL_EX = LocalException(msg='get kmx url error', rc=2)
REST_API_EX = LocalException(msg='metadata dataservice connect error', rc=3)
METADATA_EX = LocalException(msg='device deviceType not match', rc=4)
BINARY_EX = LocalException(msg='parser binary file', rc=5)

class FileAnalysis(object):
    def __init__(self, describe_file):
        self.describe_file = describe_file
        self.binary_file = ''
        self.genlab=''
        self.access = ''
        self.recl = ''
        self.variables = []
        self.varunits = []
        self.format = np.float32
        self.dimens = []
        self.ndimens = 0
        self.section = 0
        self.HEADREC = 0
        self.axivals = []
        self.__analysis__()

    def describename(self):
        return os.path.basename(self.describe_file)

    def binaryname(self):
        return self.binary_file

    # 返回当前 %mn 文件的所有变量
    def getvars(self):

        return self.variables

    def setvars(self):
        pass

    # 获取截面信息
    def getsection(self):
        # print self.describe_file
        # print 'Sections:', self.section
        return self.section

    def getaxivals(self):
        # print self.describe_file
        # print 'Sections:', self.section
        return self.axivals

    def getvarunits(self):
        return self.varunits

    # 获取每个截面的行数
    def getrow(self):
        if self.ndimens in [2, 3]:
            return self.dimens[-1]

    def getdict(self):
        _dict = {}
        _dict['binary'] = self.binary_file
        _dict['access'] = self.access
        _dict['format'] = self.format
        _dict['ndimens'] = self.ndimens
        _dict['dimens'] = self.dimens
        _dict['variables'] = self.variables
        _dict['recl'] = self.recl
        return _dict

    # 解析 %mn 文件
    def __analysis__(self):
        binary_re = re.compile(r'^FILE\s+(.+)\r$', re.M)
        access_re = re.compile(r'^ACCESS\s+([A-Z])\r*', re.M)
        genlab_re = re.compile(r'^GENLAB\s+(.+)\r*', re.M)
        format_re = re.compile(r'^FORMAT\s+([A-Z])\r*', re.M)
        ndimens_re = re.compile(r'^NDIMENS\s+([0-9])\r$', re.M)
        dimens_re = re.compile(r'^DIMENS\s+(.+)\r$', re.M)
        variab_re = re.compile(r'^VARIAB\s+(.+)\r$', re.M)
        headrec_re = re.compile(r'^HEADREC\s+([0-9]+)$', re.M)
        axival_re = re.compile(r'^AXIVAL\s+(.+)\r$', re.M)
        varunit_re = re.compile(r'^VARUNIT\s+(.+)\r$', re.M)

        with open(self.describe_file, mode='r') as f:
            data = f.read()
            #
            (self.binary_file,) = binary_re.findall(data)
            self.binary_file = os.path.join(os.path.dirname(self.describe_file),
                                            self.binary_file.strip("'\""))
            if not os.path.exists(self.binary_file):
                logging.error(
                    'Cannot found binary file %s' % (self.binary_file))
                # sys.exit(BINARY_EX.rc)
            #
            (genlab,) = genlab_re.findall(data)
            genlab=genlab.strip('\r').strip()
            self.genlab=genlab.replace("'","")

            (self.access,) = access_re.findall(data)
            if self.access not in ['D', 'S']:
                logging.error('Get unusal Access %s in %s' % (
                    self.access, self.describe_file))
                sys.exit(BINARY_EX.rc)
            #

            try:
                (value,) = format_re.findall(data)
            except ValueError:
                self.format = np.float32
            else:
                if value in ['R4', 'R*4']:
                    self.format = np.float32
                elif value in ['R8', 'R*8']:
                    self.format = np.float64
                elif value in ['I2', 'I*2']:
                    self.format = np.int16
                elif value in ['I4', 'I*4']:
                    self.format = np.int32
                else:
                    self.format = np.float32
            #
            (self.ndimens,) = ndimens_re.findall(data)
            self.ndimens = int(self.ndimens)
            if self.ndimens > 3:
                logging.error('Unsupported  number %d of dimensions in %s' % (
                    self.ndimens, self.describe_file))
                sys.exit(BINARY_EX.rc)
            #
            (self.dimens,) = dimens_re.findall(data)
            self.dimens = tuple([int(d) for d in self.dimens.split()])
            if self.ndimens == 2:
                self.section = 0
            elif self.ndimens == 3:
                self.section = self.dimens[1]
            #
            (variables,) = variab_re.findall(data)
            variables = (v for v in variables.replace("''", "' '").split())
            self.variables = list(self.combine(variables))
            #
            m = headrec_re.search(data)
            if m:
                self.HEADREC = int(m.group(1))
            else:
                self.HEADREC = 0
            if self.ndimens > 2:
                (axivals,) = axival_re.findall(data)
                self.axivals = axivals.split()
            (varunits,) = varunit_re.findall(data)
            self.varunits = varunits.split()

    # 解析binary文件
    def saveascii(self, fpath):
        if not os.path.exists(self.binary_file):
            return
        if self.access == 'D':
            dt = np.dtype((self.format, self.dimens[0]), align=True)
            binarydata = np.fromfile(self.binary_file, dtype=dt, count=-1)
            np.savetxt(fpath, binarydata, fmt='%.6E', delimiter=',',header=','.join(self.variables),comments='')
        elif self.access == 'S':

            dt = np.dtype((self.format, self.dimens[0]), align=True)
            data = np.loadtxt(self.binary_file)
            np.savetxt(fpath,data,delimiter=',',header=','.join(self.variables),comments='')

    def ndarray(self):

        if not os.path.exists(self.binary_file) or self.access not in ['D','S']:
            logging.error("Can not find %s"%(self.binary_file))
            if self.section == 0:
                return np.full((self.dimens[-1],self.dimens[0]),np.NAN)
            else:
                return np.full((self.dimens[-1]*self.section,self.dimens[0]),np.NAN)

        if self.access == 'D':
            dt = np.dtype((self.format, self.dimens[0]), align=True)
            binarydata = np.fromfile(self.binary_file, dtype=dt, count=-1)
            # np.savetxt(fpath, binarydata, fmt='%.6E', delimiter=',',header=','.join(self.variables),comments='')
        else:

            dt = np.dtype((self.format, self.dimens[0]), align=True)
            binarydata = np.loadtxt(self.binary_file)
            # np.savetxt(fpath,data,delimiter=',',header=','.join(self.variables),comments='')

        if self.section ==0:
            return binarydata.reshape((self.dimens[-1],self.dimens[0]))
        else:
            return binarydata.reshape((self.dimens[-1]*self.section,self.dimens[0]))

    # parse variable
    def combine(self, variables):
        flag = False
        tmp_v = ''
        for v in variables:
            if v[0] == "'":
                flag = True
                tmp_v = v
            elif flag:
                tmp_v += ' ' + v
                if v[-1] == "'":
                    flag = False
                    yield tmp_v.strip("'")
                    continue
            if not flag:
                yield v
